use std::any::Any;
use std::collections::HashMap;
use std::panic::panic_any;
use bytes::{Buf, BufMut, BytesMut};
use rpc::RpcResult;

struct Header {
    path: String,
    status: i32,
}

trait EncodeHeader: Any {
    fn encode_header(&mut self, header: Header) -> RpcResult<()>;
}

trait DecodeHeader: Any {
    fn decode_header(&mut self) -> RpcResult<Header>;
}

trait Encode<T> : EncodeHeader {
    fn encode(&mut self, data: T) -> RpcResult<()>;
}

trait Decode<T> : DecodeHeader {
    fn decode(&mut self) -> RpcResult<T>;
}

struct JsonCodec {
    data: String,
}

impl JsonCodec {
    fn new() -> Self {
        Self { data: String::new() }
    }
}

impl EncodeHeader for JsonCodec {
    fn encode_header(&mut self, header: Header) -> RpcResult<()> {
        self.data.push_str(&header.path);
        self.data.push_str("\r\n");
        self.data.push_str(&header.status.to_string());
        self.data.push_str("\r\n");
        Ok(())
    }
}

impl <T: ToString>Encode<T> for JsonCodec {
    fn encode(&mut self, data: T) -> RpcResult<()> {
        self.data.push_str(&data.to_string());
        Ok(())
    }
}

impl DecodeHeader for JsonCodec {
    fn decode_header(&mut self) -> RpcResult<Header> {
        let lines: Vec<&str> = self.data.split("\r\n").collect();
        let path = lines[0].to_string();
        let status_str = lines[1].to_string();
        let status = status_str.parse::<i32>()?;
        Ok(Header { path, status })
    }
}

impl <T: From<String>> Decode<T> for JsonCodec {
    fn decode(&mut self) -> RpcResult<T> {
        let t = T::from(self.data.to_string());
        Ok(t)
    }
}

struct BinaryCodec {
    data: Vec<u8>,
}

impl BinaryCodec {
    fn new() -> Self {
        Self { data: Vec::new() }
    }
}

impl EncodeHeader for BinaryCodec {
    fn encode_header(&mut self, header: Header) -> RpcResult<()> {
        let path_b = header.path.as_bytes().to_vec();
        self.data.put_u16(path_b.len() as u16);
        self.data.put_slice(&path_b[..]);
        self.data.put_i32(header.status);
        Ok(())
    }
}

impl <T: Into<Vec<u8>>>Encode<T> for BinaryCodec {
    fn encode(&mut self, data: T) -> RpcResult<()> {
        let bytes = data.into();
        self.data.put_u16(bytes.len() as u16);
        self.data.put_slice(&bytes[..]);
        Ok(())
    }
}

impl DecodeHeader for BinaryCodec {
    fn decode_header(&mut self) -> RpcResult<Header> {
        let mut bytes_mut = BytesMut::from(&self.data[..]);
        let len = bytes_mut.get_u16() as usize;
        let d = bytes_mut.copy_to_bytes(len);
        let path = String::from_utf8(d.to_vec())?;
        let status = bytes_mut.get_i32();
        Ok(Header { path, status })
    }
}

impl <T: From<Vec<u8>>>Decode<T> for BinaryCodec {
    fn decode(&mut self) -> RpcResult<T> {
        let t = T::from(self.data.to_vec());
        Ok(t)
    }
}


#[test]
fn cast_test() {
    let mut map: HashMap<&'static str, Box<dyn Any>> = HashMap::new();
    map.insert("json", Box::new(JsonCodec::new()));
    map.insert("binary", Box::new(BinaryCodec::new()));

    let t = map.get("json").unwrap();
    let c1 = cast1::<String>(t).unwrap();
    let c2 = cast2(t).unwrap();
    let c3 = cast3(t).unwrap();

    let t = JsonCodec::new();
    test::<String>(&t);
}

fn cast1<T: ToString>(any: &Box<dyn Any>) -> Option<Box<&dyn Encode<T>>> {
    if let Some(codec) = any.downcast_ref::<JsonCodec>() {
        // test(codec);
        return Some(Box::new(codec));
    }
    None
}

fn test<T: ToString>(encode: &dyn Encode<T>) {

}

fn cast2(any: &Box<dyn Any>) -> Option<&dyn EncodeHeader> {
    if let Some(t) = any.downcast_ref::<JsonCodec>() {
        return Some(t);
    }
    None
}

fn cast3(any: &Box<dyn Any>) -> Option<&dyn DecodeHeader> {
    if let Some(t) = any.downcast_ref::<JsonCodec>() {
        return Some(t);
    }
    None
}

// fn cast3<T: EncodeHeader>(any: &Box<dyn Any>) -> Option<Box<&T>> {
//     if let Some(codec) = any.downcast_ref::<JsonCodec>() {
//         return Some(Box::new(codec));
//     }
//     None
// }